package com.monkey.completablefuture;

import com.sun.org.apache.bcel.internal.generic.NEW;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.core5.concurrent.DefaultThreadFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * User: zhangqi
 * Date: 2024/8/24
 *
 * @Description: CompletableFuture学习
 */

@Slf4j
public class ComplateFuturePractice {


    private static ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
            4,
            8,
            5,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            new DefaultThreadFactory("CompletableFuture"),
            new ThreadPoolExecutor.AbortPolicy());

    /**
     * https://juejin.cn/post/7140244126679138312
     */
    @SneakyThrows
    public static void main(String[] args) {

        /**
         * 1.无返回值的单个任务--runAsync
         */
        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(()-> {
            System.out.println("无返回值的单个任务！");
        }, threadPoolExecutor);
        threadPoolExecutor.shutdown();

        /**
         * 2.有返回值--supplyAsync
         * 2.1:whenComplete：能感知异常，能感知结果，但没办法给返回值
         * 2.2:exceptionally：能感知异常，不能感知结果，能给返回值。相当于，如果出现异常就返回这个值
         * 2.3:handle:能拿到返回结果，也能得到异常信息，也能修改返回值
         */
        CompletableFuture<String> suppliedAsync = CompletableFuture.supplyAsync(() -> {
            return "有返回值的方法!";
        }, threadPoolExecutor).whenComplete((res,exception)->{

        }).exceptionally((exception)->"exceptionally!").handle((res,exception)->{
            return res+"111";
        });
        String str = suppliedAsync.get();
        System.out.println(str);
        //-----------------------------------------------------------------------------------------------

        /**
         * 3.两个任务的执行
         * 3.1:thenRunAsync 不能接收上一次的执行结果，也没返回值
         * 3.2:thenAcceptAsync 能接收上一次的执行结果，但没返回值
         * 3.3:thenApplyAsync 能接收上一次的执行结果，又可以有返回值
         */
        CompletableFuture<Object> suppliedAsyncTwo = CompletableFuture.supplyAsync(() -> {
            return "first task!";
        }, threadPoolExecutor);
        suppliedAsyncTwo.thenAccept((res)->{
            System.out.println("thenRunAsync:接收第一次的执行结果!"+res);
        });
        CompletableFuture<String> thennedApplyAsync = suppliedAsyncTwo.thenApplyAsync((res) -> {
            System.out.println("thenApplyAsync:接收第一次的执行结果!" + res);
            return "thenApplyAsync:" + res;
        });
        System.out.println(thennedApplyAsync.get()+"222");


        /**
         * 4.三个任务的编排 三任务组合，前两个任务都完成，才执行任务3
         * 4.1:runAfterBothAsync：任务01 任务02都完成了，再开始执行任务3，不感知任务1、2的结果的，也没返回值
         * 4.2:thenAcceptBothAsync：任务01 任务02都完成了，再开始执行任务3，能感知到任务1、2的结果，但没返回值
         * 4.3:thenCombineAsync：任务01 任务02都完成了，再开始执行任务3，能感知到任务1、2的结果，而且自己可以带返回值
         */
        //准备两个任务
        CompletableFuture<Object> future01 =CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1结束：");
            return i;
        }, threadPoolExecutor);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程" + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
                System.out.println("任务2结束：");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
        }, threadPoolExecutor);

        //4.1
        CompletableFuture<Void> future4_1 = future01.runAfterBothAsync(future02, () -> {
            System.out.println("任务3开始");
        }, threadPoolExecutor);
        //4.2
        CompletableFuture<Void> future4_2 = future01.thenAcceptBothAsync(future02, (f1, f2) -> {
            System.out.println("任务3开始...得到之前的结果：f1:" + f1 + ", f2:" + f2);
        }, threadPoolExecutor);
        //4.3
        CompletableFuture<String> future4_3 = future01.thenCombineAsync(future02, (f1, f2) -> {
            return f1+":"+f2+"：哈哈";
        }, threadPoolExecutor);

        /**
         *  5 三任务组合，前两个任务只要有一个完成，就执行任务3
         *  5.1:runAfterEitherAsync：两个任务只要有一个完成，就执行任务3，不感知结果，自己没返回值
         *  5.2:acceptEitherAsync：两个任务只要有一个完成，就执行任务3，感知结果，自己没返回值
         *  5.3:applyToEitherAsync：两个任务只要有一个完成，就执行任务3，感知结果，自己有返回值
         */
        //5.1
        CompletableFuture<Void> future5_1 = future01.runAfterEitherAsync(future02, () -> {
            System.out.println("任务3开始...");
        }, threadPoolExecutor);

        CompletableFuture<Void> future5_2 = future01.acceptEitherAsync(future02, (res) -> {
            System.out.println("任务3开始...之前的结果" + res);
        }, threadPoolExecutor);

        CompletableFuture<String> future5_3 = future01.applyToEitherAsync(future02, (res) -> {
            System.out.println("任务3开始...之前的结果" + res);
            return "任务3的结果...";
        }, threadPoolExecutor);

        /**
         * 6 多任务编排
         * 6.1 allOf：所有任务都执行完
         * 6.2 anyOf：其中有一个任务执行完就可以
         */

        /**
         * allOf 所有任务都执行完
         */
        CompletableFuture<Void> allOf = CompletableFuture.allOf(future5_1, future5_2, future5_3);
        allOf.get();//等待所有结果完成
    }
}
